home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / GraphicViewers / pCD / Source / Photo_CD.subproj / photoCD_Rdr.m < prev    next >
Text File  |  1993-03-27  |  10KB  |  395 lines

  1. /*
  2.  * This class contains everything we know about the format of information
  3.  * on a Photo_CD.  Note that this knowledge is not complete, it's just
  4.  * as much as has been deciphered by the hpcdtoppm program written by
  5.  * Hadmut Danisch (danisch@ira.uka.de).  Some comments from that program:
  6.  
  7.  * hpcdtoppm (Hadmut's pcdtoppm) v0.3
  8.  * Copyright (c) 1992 by Hadmut Danisch (danisch@ira.uka.de).
  9.  * Permission to use and distribute this software and its
  10.  * documentation for noncommercial use and without fee is hereby granted,
  11.  * provided that the above copyright notice appear in all copies and that
  12.  * both that copyright notice and this permission notice appear in
  13.  * supporting documentation. It is not allowed to sell this software in 
  14.  * any way. This software is not public domain.
  15.  
  16.  * Some of that program is reimplemented in this class, and the rest is
  17.  * still (currently) off in some C source and header files.
  18.  * These comments by:
  19.  *            Garance Alistair Drosehn;  Jan 14th, 1993
  20. */
  21.  
  22. #import "photoCD_Rdr.h"
  23.  
  24. #import "pcd.h"
  25. #define PCD_READ_OK    0
  26. #define PCD_READ_ERROR    1
  27. #define PCD_READBUF { \
  28.     if ( READBUF < 1 ) { \
  29.         NXRunAlertPanel(0, \
  30.         " Unexpected eof while reading", \
  31.         0, 0, 0); \
  32.         } \
  33.      }
  34. #define PCD_SEEK(x) { \
  35.     if (fseek(fin,((x) * SECSIZE),0)) { \
  36.         NXRunAlertPanel(0, \
  37.         " Unexpected error from fseek to sector %d", \
  38.         0, 0, 0, (x)); \
  39.         } \
  40.      }
  41.  
  42. extern void rotateBm( dim *w, dim *h, implane *r, implane *g, implane *b, enum TURNS t);
  43.  
  44. @implementation photoCD_Rdr
  45.  
  46. /* methods only called from within this class */
  47. - (NXBitmapImageRep *) _allocBitmap
  48.          :(dim)width :(dim)height
  49.       red:(uBYTE *)redPlane 
  50.     green:(uBYTE *)greenPlane
  51.      blue:(uBYTE *)bluePlane
  52. {
  53.     u_char    *rgb[5];
  54.     NXBitmapImageRep    *bitmap;
  55.  
  56.     rgb[0] = redPlane;
  57.     rgb[1] = greenPlane;
  58.     rgb[2] = bluePlane;
  59.     rgb[3] = NULL;
  60.     rgb[4] = NULL;
  61.  
  62.     /* allocate the proper sized BitmapImage and use the planes
  63.        allocated by that for our processing */
  64.     bitmap = [[NXBitmapImageRep alloc] initDataPlanes:rgb 
  65.             pixelsWide:width 
  66.             pixelsHigh:height 
  67.             bitsPerSample:8 
  68.             samplesPerPixel:3 
  69.             hasAlpha:NO 
  70.             isPlanar:YES 
  71.             colorSpace:NX_RGBColorSpace 
  72.             bytesPerRow:0 
  73.             bitsPerPixel:0];
  74.     if ( ! bitmap ) {
  75.     NXRunAlertPanel(0,
  76.         " Unable to allocate bitmap for a %d x %d image",
  77.         0, 0, 0, width, height);
  78.     /* probably should so something less drastic here */
  79.     exit(9);
  80.     }
  81.     
  82.     return bitmap;
  83.  }
  84.  
  85.  
  86. - (short)_getExpectedThumbnailCount
  87. {
  88.     /* assume that the caller is reading an overview file */
  89.     struct ph0        *d;
  90.  
  91.     PCD_SEEK(0);
  92.     PCD_READBUF;
  93.     d = (struct ph0 *) sbuffer;
  94.     return d->num_thumbs;
  95. }
  96.  
  97.  
  98. - setDoSharp:(BOOL)wantsDoSharp
  99. {
  100.     mainSetSharpit( wantsDoSharp );
  101.     return self;
  102. }
  103.  
  104.  
  105. - setNextGammaCorrection:(BOOL)wantsNextCorr
  106. {
  107.     if( wantsNextCorr) mainSetGammaCorr(C_NeXT);
  108.     else mainSetGammaCorr(C_LINEAR);
  109.     return self;
  110. }
  111.  
  112.  
  113. - (int)readOverviewFromFile:(char *)ovFil
  114.           curImageCount:(int)initialImageCount
  115.              ImageArray:(ovImageArray *)imageArrayPtr
  116.          MaxEntries:(int)overviewReadMax  /* note: settable */
  117. {
  118.     dim        w, h;
  119.     implane    Luma, Chroma1, Chroma2;
  120.  
  121.     NXBitmapImageRep    *bm;
  122.     int        pictNumber, imageCount, expectedCount, readStatus;
  123.     char    statStr[45];
  124.  
  125.     fin=fopen(ovFil,"r");
  126.     if ( !fin ) {
  127.     NXRunAlertPanel(0,
  128.         " Unable to open overview file %s",
  129.         0, 0, 0, ovFil);
  130.     return -1;
  131.     }
  132.     
  133.     /*  free overview images from previous photo_cd (if any) */
  134.     for( ; initialImageCount > 0; initialImageCount-- ) {
  135.     bm = (*imageArrayPtr)[initialImageCount];
  136.     if ( bm != nil ) {
  137.         (*imageArrayPtr)[initialImageCount] = nil;
  138.         [bm free];
  139.         }
  140.     }
  141.     initialImageCount = imageCount = 0;
  142.     bm = nil;
  143.     
  144.     expectedCount = [self _getExpectedThumbnailCount];
  145.  
  146.     [readStatusField setStringValue:"Processing thumbnails"];
  147.     [readStatusPanel makeKeyAndOrderFront:self];
  148.  
  149.     w=BaseW/4;
  150.     h=BaseH/4;
  151.     
  152.     pictNumber = 1;
  153.     while ( (!feof(fin)) && (pictNumber <= overviewReadMax) ) {
  154.  
  155.     /* Display a status message for each image, and call
  156.      * NXPing every 4 images to make sure the status messages
  157.      * are seen by the user.  Without the call to NXPing, the
  158.      * messages are buffered up, and aren't displayed until
  159.      * that buffer is full.
  160.      */
  161.     sprintf(statStr, "Reading Thumbnail # %d", pictNumber);
  162.     [readStatusField setStringValue:statStr];
  163.     if ( (pictNumber % 4) == 0 ) NXPing();
  164.     
  165.     /* allocate the buffers */
  166.     planealloc(&Luma,    w,h);
  167.     planealloc(&Chroma1, w,h);
  168.     planealloc(&Chroma2, w,h);
  169.  
  170.     PCD_SEEK(5 + SeBase16 * (pictNumber - 1));
  171.     readStatus = readplain(w, h, &Luma, &Chroma1, &Chroma2, fin);
  172.     if (readStatus != PCD_READ_OK) {
  173.         if (    (readStatus == PCD_READ_ERROR) 
  174.              && ( imageCount == expectedCount)  ) {
  175.         /* not a problem, no error message to write */
  176.         }
  177.         else {
  178.         /*  more noticable error indication, as none of the
  179.          *  other errors should ever happen.
  180.          */
  181.         NXRunAlertPanel(0,
  182.             " Unexpected error (%d) from readplain in"
  183.             " readOverview processing for picture #%d"
  184.             " in file %s",
  185.             0, 0, 0, readStatus, pictNumber, ovFil);
  186.         }
  187.         break;
  188.         }
  189.     interpolate(&Chroma1);
  190.     interpolate(&Chroma2);
  191.     colconvert(&w,&h,&Luma,&Chroma1,&Chroma2);
  192.     /* at this point Luma is Red, Chroma1 is Green, Chroma2 is Blue */
  193.  
  194.     bm = [self _allocBitmap :w :h
  195.         red:Luma.im green:Chroma1.im blue:Chroma2.im];
  196.  
  197.     imageCount = pictNumber;
  198.     (*imageArrayPtr)[imageCount] = bm;
  199.     
  200.     pictNumber++;            /* try for next picture */
  201.     }
  202.     
  203.     fclose(fin);
  204.     fin = 0x0;
  205.  
  206.     if ( imageCount != expectedCount ) {
  207.     /* just a simple error message to console */
  208.     printf("Read in %d overview pictures, but %d were expected in %s\n",
  209.         imageCount, expectedCount, ovFil);
  210.     }
  211.  
  212.     [readStatusPanel close];
  213.     return imageCount;
  214. }
  215.  
  216.  
  217. - readBitmapFromFile:(char *)imFile atSize:(enum is_Tags)imageSize
  218. {
  219.     dim        w, h, rp_w, rp_h;
  220.     int        seekPos = -1, cd_offset = -1;
  221.     implane    Luma, Chroma1, Chroma2;
  222.     NXBitmapImageRep  *bm;
  223.     int        readStatus;
  224.     enum TURNS    turn=T_NONE;
  225.  
  226.     fin=fopen(imFile,"r");
  227.     if ( !fin ) {
  228.     NXRunAlertPanel(0, " Unable to open image file %s",
  229.         0, 0, 0, imFile);
  230.     return nil;
  231.     }
  232.  
  233.     switch ( imageSize ) {
  234.     case is_Base16_TAG:
  235.         w = rp_w = BaseW / 4;
  236.         h = rp_h = BaseH / 4;
  237.         seekPos = L_Head + 1;
  238.         break;
  239.     case is_Base4_TAG:  
  240.         w = rp_w = BaseW / 2;
  241.         h = rp_h = BaseH / 2;
  242.         seekPos = L_Head + L_Base16 + 1;
  243.         break;
  244.     case is_4Base_TAG:
  245.         w = 2 * BaseW;
  246.         rp_w = BaseW;
  247.         h = 2 * BaseH;
  248.         rp_h = BaseH;
  249.         seekPos = L_Head + L_Base16 + L_Base4 + 1;    // sic
  250.         break;
  251.     case is_16Base_TAG:
  252.         //    this option does seem to work, but it's currently
  253.         //    disabled in the preferences panel because it uses
  254.         //    *huge* amounts of VM...
  255.         w = 4 * BaseW;
  256.         rp_w = BaseW;
  257.         h = 4 * BaseH;
  258.         rp_h = BaseH;
  259.         seekPos = L_Head + L_Base16 + L_Base4 + 1;    // sic
  260.         break;
  261.     default:
  262.         //     the correct values for case is_Base_TAG.
  263.         w = rp_w = BaseW;
  264.         h = rp_h = BaseH;
  265.         seekPos = L_Head + L_Base16 + L_Base4 + 1;
  266.         break;
  267.     }
  268.  
  269.     /* allocate the buffers */
  270.     planealloc(&Luma,    w,h);
  271.     planealloc(&Chroma1, w,h);
  272.     planealloc(&Chroma2, w,h);
  273.  
  274.     PCD_SEEK(1); PCD_READBUF;
  275.     switch(sbuffer[0xe02 & 0x7ff]&0x03) {
  276.     case 0x00: turn=T_NONE;  break;
  277.     case 0x01: turn=T_LEFT;  break;
  278.     case 0x03: turn=T_RIGHT; break;
  279.     default:
  280.         NXRunAlertPanel(0,
  281.             " Unexpected “turn” in pickImage processing",
  282.             0, 0, 0);
  283.         fclose(fin);        // perform some clean-up
  284.         fin = 0x0;
  285.         return nil;        // can't process the picture
  286.     }
  287.  
  288.     PCD_SEEK( seekPos );
  289.     readStatus = readplain(rp_w, rp_h, &Luma, &Chroma1, &Chroma2, fin);
  290.     if ( readStatus != PCD_READ_OK ) {
  291.     NXRunAlertPanel(0,
  292.         " Unexpected error (%d) from readplain in pickImage"
  293.         " processing for image at w=%d, h=%d",
  294.         0, 0, 0, readStatus, rp_w, rp_h);
  295.     fclose(fin);        // perform some clean-up
  296.     fin = 0x0;
  297.     return nil;        // can't process the picture
  298.     }
  299.     interpolate(&Chroma1);
  300.     interpolate(&Chroma2);
  301.     if ( w != rp_w ) {        // ie, is_4Base_TAG or is_16Base_TAG
  302.     //   these image sizes need more interpolate-tion calls
  303.     interpolate(&Luma);
  304.     interpolate(&Chroma1);
  305.     interpolate(&Chroma2);
  306.  
  307.     //   They also need this readhqt/decode processing.
  308. #define nullplane ((implane *) 0)
  309.     switch ( imageSize ) {
  310.         case is_4Base_TAG:
  311.         cd_offset = L_Head + L_Base16 + L_Base4 + L_Base;
  312.         PCD_SEEK(cd_offset + 4);
  313.         readhqt(w, h, 1, fin);
  314.         PCD_SEEK(cd_offset + 5);
  315.         decode(w, h, &Luma, nullplane, nullplane, 0, fin);
  316.         break;
  317.         case is_16Base_TAG:
  318.         cd_offset = L_Head + L_Base16 + L_Base4 + L_Base;
  319.         PCD_SEEK(cd_offset + 4);
  320.         readhqt(w / 2, h / 2, 1, fin);
  321.         PCD_SEEK(cd_offset + 5);
  322.         decode(w / 2, h / 2, &Luma, nullplane, nullplane, 0, fin);
  323.         interpolate(&Luma);
  324.     
  325.         cd_offset = ftell(fin);
  326.         if (cd_offset % SECSIZE) {
  327.             NXRunAlertPanel(0,
  328.             " Base16 Position error in pickImage",
  329.             0, 0, 0);
  330.             fclose(fin);        // perform some clean-up
  331.             fin = 0x0;
  332.             return nil;        // can't process the picture
  333.             }
  334.         cd_offset /= SECSIZE;
  335.     
  336.         PCD_SEEK(cd_offset + 12);
  337.         readhqt(w, h, 3, fin);
  338.         PCD_SEEK(cd_offset + 14);
  339.         decode(w, h, &Luma, &Chroma1, &Chroma2, 0, fin);
  340.     
  341.         interpolate(&Chroma1);
  342.         interpolate(&Chroma2);
  343.         break;
  344.         default:
  345.         NXRunAlertPanel(0, " Internal error in pickImage",
  346.             0, 0, 0);
  347.         fclose(fin);        // perform some clean-up
  348.         fin = 0x0;
  349.         return nil;        // can't process the picture
  350.         }
  351. #undef nullplane
  352.  
  353.     }
  354.  
  355.     colconvert(&w,&h,&Luma,&Chroma1,&Chroma2);
  356.     /* at this point Luma is Red, Chroma1 is Green, Chroma2 is Blue */
  357.  
  358.     if( turn != T_NONE ) {
  359.     rotateBm(&w, &h, &Luma, &Chroma1, &Chroma2, turn);
  360.     }
  361.     
  362.     bm = [self _allocBitmap :w :h
  363.         red:Luma.im green:Chroma1.im blue:Chroma2.im];
  364.  
  365.     fclose(fin);
  366.     fin = 0x0;
  367.  
  368.     /* note that anyone freeing this bitmap will also have to know
  369.        to free the RGB buffers that it's using */
  370.     return bm;
  371. }
  372.  
  373.  
  374. /* note that nobody calls this yet, instead there's code that's
  375.    mighty similar to this over in PhotoWinProcs.  Oops.
  376. */
  377. - freeDataPlanes:(NXBitmapImageRep *)imgBitmap
  378. {
  379.     u_char    *rgb[5];
  380.  
  381.     if ( [imgBitmap isPlanar] ) {
  382.     /* a rather sleezy way to distinguish between images that
  383.        were read in and images which were cut/pasted in...  */
  384.     [imgBitmap getDataPlanes:rgb];
  385.     if ( rgb[0] ) free( rgb[0] );
  386.     if ( rgb[1] ) free( rgb[1] );
  387.     if ( rgb[2] ) free( rgb[2] );
  388.     }
  389.  
  390.     return self;
  391. }
  392.  
  393.  
  394. @end
  395.